# coding=utf-8
import os
import re
import time
from tkinter import *
from tkinter import filedialog
from tkinter import font
from tkinter import messagebox
from tkinter.ttk import Combobox
from openpyxl import load_workbook
from MergeExcel.core import multiple_excel_merge_single_sheet, multiple_sheet_merge_single_sheet
from utils.file import get_file_list, write_config, read_config
from utils import is_not_empty


class MySimpleGUI:
    """
        合并的类型：合并多个工作簿、合并多个工作表
        选择文件夹/选择文件：【】
        从第【】行开始合并
        确定
    """

    def __init__(self, window):
        """
        初始化窗口
        :param window:
        """
        self.window = window
        # 初始化数据
        self.merge_types = ["合并多个工作簿",
                            "合并多个工作表"]
        # 尝试读取配置文件
        init_config = {
            "merge_type": self.merge_types[0],
            "path": "",
            "start_row": 2,
        }
        init_config.update(read_config())  # 合并配置文件
        # 初始化控件变量
        self.merge_type_var = StringVar(value=init_config["merge_type"])  # 合并类型
        self.path_var = StringVar(value=init_config["path"])  # 文件夹路径
        self.start_row_var = IntVar(value=int(init_config["start_row"]))  # 合并起始行
        # 初始化控件
        self.start_row_spinbox = None
        self.path_button = None
        self.enter_button = None  # 确定按钮
        self.progress_label = None  # 显示过程标签

    def set_window_style(self):
        """
        设置窗口样式
        :return:
        """
        screen_width = self.window.winfo_screenwidth()
        screen_height = self.window.winfo_screenheight()
        width, height = 400, 240
        x = int(screen_width / 2 - width / 2)
        y = int(screen_height / 2 - height / 2)
        size = '{}x{}+{}+{}'.format(width, height, x, y)  # 设置宽高和居中显示
        self.window.geometry(size)
        self.window.title("合并Excel-王凤龙")

    def set_window_menu(self):
        """
        设置菜单
        :return:
        """
        menu_bar = Menu(self.window)
        menu_bar.add_command(label="联系我", command=lambda: messagebox.showinfo("联系我", "微信号：i-aisx"))
        menu_bar.add_command(label="保存配置", command=lambda: self.save_config())
        menu_bar.add_command(label="关闭", command=lambda: self.window.destroy())
        self.window.config(menu=menu_bar)

    def set_window_layout(self):
        """
        设置窗口布局
        :return:
        """
        """选择合并类型"""
        merge_type_frame = Frame(self.window)
        Label(merge_type_frame, text='合并的类型：', width=12).pack(side=LEFT, padx=5)
        merge_type_combobox = Combobox(merge_type_frame, values=self.merge_types, textvariable=self.merge_type_var)
        merge_type_combobox.bind("<<ComboboxSelected>>", self.merge_type_handle)
        merge_type_combobox.pack(side=LEFT, padx=5, fill=X, expand=True)
        merge_type_frame.pack(pady=10, fill=X)
        """选择目录"""
        path_frame = Frame(self.window)  # 创建文件夹选择框架
        self.path_button = Button(path_frame, width=10, cursor="hand2", command=self.open_path)
        self.path_button["text"] = '选择文件夹' if self.merge_type_var.get() == self.merge_types[0] else "选择文件"
        self.path_button.pack(side=LEFT, padx=5)
        Entry(path_frame, textvariable=self.path_var) \
            .pack(side=LEFT, padx=5, fill=X, expand=True)  # 自动填充X轴方向剩余宽度
        path_frame.pack(pady=10, fill=X)  # 框架靠左显示，并占满X轴（对齐方式）
        """合并起始行"""
        start_row_frame = Frame(self.window)
        Label(start_row_frame, text='从第').pack(side=LEFT, padx=5)
        self.start_row_spinbox = Spinbox(start_row_frame, width=5, justify=CENTER,
                                         from_=0, to=10, increment=1, textvariable=self.start_row_var)
        self.start_row_spinbox.pack(side=LEFT, padx=5)
        Label(start_row_frame, text='行开始合并').pack(side=LEFT, padx=5)
        start_row_frame.pack(pady=10, fill=X)
        """确定"""
        self.enter_button = Button(self.window, text='确定', cursor="hand2", width=8, command=self.enter_handle,
                                   font=font.Font(size=16, weight="bold"))
        self.enter_button.pack(pady=20)
        """读取过程"""
        self.progress_label = Label(self.window, text='')
        self.progress_label.pack(side=LEFT, padx=5)
        """更新文件信息"""
        # self.update_file()

    def open_path(self):
        """
        打开文件或者文件夹
        :return:
        """
        merge_type = self.merge_type_var.get()
        if merge_type == self.merge_types[0]:
            path = filedialog.askdirectory()
        if merge_type == self.merge_types[1]:
            path = filedialog.askopenfilename()
        if is_not_empty(path):
            self.path_var.set(path)
            self.update_file()

    def merge_type_handle(self, event=None):
        """
            合并类型处理
        """
        merge_type = self.merge_type_var.get()
        if merge_type == self.merge_types[0]:
            self.path_button["text"] = "选择文件夹"
        if merge_type == self.merge_types[1]:
            self.path_button["text"] = "选择文件"
        self.path_var.set("")

    def update_file(self):
        """
        更新文件提示信息
        :return:
        """
        path = self.path_var.get()
        merge_type = self.merge_type_var.get()
        if is_not_empty(path):
            if merge_type == self.merge_types[0]:
                files = get_file_list(path, ".xlsx")
                self.progress_label["text"] = "发现{}个工作簿".format(len(files))
            if merge_type == self.merge_types[1]:
                wb = load_workbook(path, read_only=True)
                self.progress_label["text"] = "发现{}个工作表".format(len(wb.sheetnames))
                wb.close()

    def enter_handle(self):
        """
        确定处理
        :return:
        """
        """获取用户输入的各个值"""
        merge_type = self.merge_type_var.get()
        path = self.path_var.get()
        start_row = self.start_row_var.get()
        """检验文件夹路径"""
        if len(path.strip()) == 0:
            messagebox.showwarning("提示", "文件夹路径不能为空")
            return
        """判断文件是否打开"""
        file_name = "汇总.xlsx"  # 默认保存文件名
        if os.path.exists(file_name):
            try:
                file = open(file_name, "a")  # 以追加方式打开
                file.close()
            except PermissionError:
                messagebox.showwarning("提示", "请先关闭已打开的【{}】".format(file_name))
                return
        """根据文件类型调用合并函数"""
        self.enter_button["state"] = DISABLED
        if merge_type == self.merge_types[0]:
            result_file = multiple_excel_merge_single_sheet(path, start_row, self.progress_show)
        else:
            result_file = multiple_sheet_merge_single_sheet(path, start_row, self.progress_show)
        result_file.save(file_name)
        messagebox.showinfo("合并完成", "已合并到【汇总.xlsx】")
        self.enter_button["state"] = NORMAL

    def progress_show(self, index, length, text):
        """
        显示处理进度
        :param index: 当前读取位置
        :param length: 总长度
        :param text: 当前读取的文件名称
        :return:
        """
        self.progress_label["text"] = "总进度({}/{}): {}".format(index + 1, length, text)
        self.progress_label.update()    # 动态刷新数据
        #   tkinter更新控件必须在主线程，由于没有返回主线程的路径，tkinter没能及时更新控件
        #   可以使用update函数强制执行一次主线程
        #   如何需要延时执行，可以使用after代替time.sleep
        #   也可以直接使用带回调函数的after函数，该函数作用是向事件循环（待办列表）中添加一个事件（回调函数）以及（延时）运行它的时间，到时间mainloop会执行回调函数
        #   例如：self.button.after(1000, func)    # 1000单位是ms，1000ms=1s，实时更新时间时可以使用


    def save_config(self):
        """
        保存配置
        :return:
        """
        write_config(configs={
            "merge_type": self.merge_type_var.get(),
            "path": self.path_var.get(),
            "start_row": self.start_row_var.get(),
        })
        messagebox.showinfo("提示", "当前配置已保存")


def start():
    """
    启动gui
    :return:
    """
    window = Tk()
    gui = MySimpleGUI(window)
    gui.set_window_style()
    gui.set_window_menu()
    gui.set_window_layout()
    window.mainloop()


if __name__ == "__main__":
    start()
